package com.brzjomo.secretiveworld.entity.passive.fish;

import java.util.List;

import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.MobEntity;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.goal.AvoidEntityGoal;
import net.minecraft.entity.ai.goal.HurtByTargetGoal;
import net.minecraft.entity.ai.goal.LookAtGoal;
import net.minecraft.entity.ai.goal.LookRandomlyGoal;
import net.minecraft.entity.ai.goal.MeleeAttackGoal;
import net.minecraft.entity.ai.goal.MoveTowardsTargetGoal;
import net.minecraft.entity.ai.goal.NearestAttackableTargetGoal;
import net.minecraft.entity.ai.goal.RandomSwimmingGoal;
import net.minecraft.entity.monster.DrownedEntity;
import net.minecraft.entity.passive.SquidEntity;
import net.minecraft.entity.passive.fish.AbstractFishEntity;
import net.minecraft.entity.passive.fish.AbstractGroupFishEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.potion.EffectInstance;
import net.minecraft.potion.Effects;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EntityPredicates;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.SoundEvents;
import net.minecraft.world.Difficulty;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import software.bernie.geckolib3.core.IAnimatable;
import software.bernie.geckolib3.core.PlayState;
import software.bernie.geckolib3.core.builder.AnimationBuilder;
import software.bernie.geckolib3.core.controller.AnimationController;
import software.bernie.geckolib3.core.event.predicate.AnimationEvent;
import software.bernie.geckolib3.core.manager.AnimationData;
import software.bernie.geckolib3.core.manager.AnimationFactory;

public class SwordFishEntity extends AbstractGroupFishEntity implements IAnimatable {
	private int timer = 0;
	private int ticks = 0;
	private AnimationFactory factory = new AnimationFactory(this);

	public SwordFishEntity(EntityType<? extends SwordFishEntity> type, World worldIn) {
		super(type, worldIn);
	}

	@Override
	public int getMaxGroupSize() {
		return 5;
	}

	public int getMaxSpawnedInChunk() {
		return this.getMaxGroupSize() * 2;
	}

	@Override
	protected ItemStack getFishBucket() {
		return new ItemStack(Items.SALMON_BUCKET);
	}

	@Override
	protected SoundEvent getAmbientSound() {
		return SoundEvents.ENTITY_SALMON_AMBIENT;
	}

	@Override
	protected SoundEvent getDeathSound() {
		return SoundEvents.ENTITY_SALMON_DEATH;
	}

	@Override
	protected SoundEvent getHurtSound(DamageSource damageSourceIn) {
		return SoundEvents.ENTITY_SALMON_HURT;
	}

	@Override
	protected SoundEvent getFlopSound() {
		return SoundEvents.ENTITY_SALMON_FLOP;
	}

	@Override
	protected void registerAttributes() {
		super.registerAttributes();
		this.getAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(14.0D);
		this.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue((double) 1.2F);
		this.getAttributes().registerAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(2.5D);
	}

	@Override
	protected void registerGoals() {
		super.registerGoals();
		this.goalSelector.addGoal(1, new MeleeAttackGoal(this, (double) 1.2F, true));
		this.goalSelector.addGoal(2, new MoveTowardsTargetGoal(this, (double) 1.2F, 32.0F));
		this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, PlayerEntity.class, 8.0F, (double) 1.2F, (double) 1.0F,
				EntityPredicates.NOT_SPECTATING::test));
		this.goalSelector.addGoal(4, new LookAtGoal(this, PlayerEntity.class, 10.0F));
		this.goalSelector.addGoal(5, new RandomSwimmingGoal(this, (double) 1.2F, 10));
		this.goalSelector.addGoal(5, new LookRandomlyGoal(this));
		this.targetSelector.addGoal(2, (new HurtByTargetGoal(this)).setCallsForHelp());
		this.targetSelector.addGoal(3,
				new NearestAttackableTargetGoal<>(this, MobEntity.class, 5, false, false, (target) -> {
					return target instanceof SquidEntity || target instanceof DrownedEntity;
				}));
	}

	@Override
	public boolean attackEntityAsMob(Entity entityIn) {
		boolean flag = entityIn.attackEntityFrom(DamageSource.causeMobDamage(this),
				(float) ((int) this.getAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).getValue()));
		if (flag) {
			this.applyEnchantments(this, entityIn);
			if (entityIn instanceof LivingEntity) {
				int i = 0;
				if (this.world.getDifficulty() == Difficulty.NORMAL) {
					i = 10;
				} else if (this.world.getDifficulty() == Difficulty.HARD) {
					i = 18;
				}

				if (i > 0) {
					((LivingEntity) entityIn).addPotionEffect(new EffectInstance(Effects.WEAKNESS, i * 10, 0));
				}
			}

			this.playSound(SoundEvents.ENTITY_BEE_STING, 1.0F, 1.0F);
		}
		return flag;
	}

	@Override
	public boolean canAttack(EntityType<?> typeIn) {
		return true;
	}

	@OnlyIn(Dist.CLIENT)
	public int getAttackTimer() {
		return 10;
	}

	@Override
	public boolean canBePushed() {
		return false;
	}

	@Override
	public boolean isPushedByWater() {
		return false;
	}

	@Override
	public void livingTick() {
		if (!this.isInWater() && this.onGround && this.collidedVertically) {
			this.rotationYaw = this.rand.nextFloat() * 360.0F;
			this.rotationPitch = this.rand.nextBoolean() == true ? this.rand.nextFloat() * 60.0F
					: this.rand.nextFloat() * 60.0F * (-1.0F);
			this.onGround = false;
			this.isAirBorne = true;
			ticks ++;
			if (ticks == 20) {
				this.playSound(this.getFlopSound(), this.getSoundVolume(), this.getSoundPitch());
				ticks = 0;
			}
		}

		super.livingTick();
	}

	@Override
	public void tick() {
		if (this.isGroupLeader() && this.world.rand.nextInt(200) == 1) {
			List<AbstractFishEntity> list = this.world.getEntitiesWithinAABB(this.getClass(),
					this.getBoundingBox().grow(8.0D, 8.0D, 8.0D));
			if (list.size() <= 1) {
				this.groupSize = 1;
			}
		}

		++this.timer;
		if (timer / 200 > 1) {
			this.heal(1.0F);
			this.timer = 0;
		}

		super.tick();
	}

	private <E extends IAnimatable> PlayState predicate(AnimationEvent<E> event) {
		if (!this.isInWater() && this.onGround) {
			event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.sword_fish.onground", true));
			return PlayState.CONTINUE;
		} else if (event.isMoving()) {
			event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.sword_fish.swimming", true));
			return PlayState.CONTINUE;
		} else if (this.isSwimming() || this.isJumping) {
			event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.sword_fish.swimming", true));
			return PlayState.CONTINUE;
		} else {
			event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.sword_fish.standing", true));
			return PlayState.CONTINUE;
		}
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public void registerControllers(AnimationData data) {
		data.addAnimationController(new AnimationController(this, "controller", 0, this::predicate));
	}

	@Override
	public AnimationFactory getFactory() {
		return this.factory;
	}
}
